//
// RS Game Framework
// Copyright © 2009 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

#include <rs/reflection/Reflection.hpp>
#include <rs/unittest/UnitTest.hpp>

namespace
{
    using namespace rs;
    using namespace rs::reflection;
    
    class TestClass
    {
        RS_DECLARE_REFLECTION();
        
    public:
        
        TestClass()
        : x(0), y(0) {
        }
        
        Int32 GetX() const {
            return x;
        }
        
        Int32 GetY() const {
            return y;
        }
        
        void SetX(int i) {
            x = i;
        }
        
        void SetY(int i) {
            y = i;
        }
        
    private:
        
        Int32 x, y;
    };
    
    RS_DEFINE_REFLECTION_CLASS(TestClass)
        .BindMethod("GetX", &TestClass::GetX)
        .BindMethod("GetY", &TestClass::GetY)
        .BindMethod("SetX", &TestClass::SetX)
        .BindMethod("SetY", &TestClass::SetY);
    
    RS_TEST_CASE(rs::reflection, MethodsUsage)
    {
        TestClass obj;
        Int32 out = -1;
        
        Class const& classRecord = obj.GetClassRecord();
        RS_ASSERT(4 == classRecord.GetMethodCount(), "wrong number of methods returned");
        
        classRecord.GetMethodViaName("GetX")(obj, &out);
        RS_ASSERT(out == obj.GetX(), "'GetX' method failed");
        
        classRecord.GetMethodViaName("GetY")(obj, &out);
        RS_ASSERT(out == obj.GetY(), "'GetY' method failed");
        
        classRecord.GetMethodViaName("SetX")(obj, 1, Method::kNull);
        RS_ASSERT(obj.GetX() == 1, "'SetX' failed");
        
        classRecord.GetMethodViaName("SetY")(obj, 1, Method::kNull);
        RS_ASSERT(obj.GetY() == 1, "'SetY' failed");
        
        classRecord.GetMethodViaName("GetX")(obj, Method::kNull);
    }
    
    RS_TEST_CASE(rs::reflection, MethodsTypes)
    {
        Class const& classRecord = ReflectionCenter::GetReflectionCenter().GetClassRecord("TestClass");
        Method const& getX = classRecord.GetMethodViaName("GetX");
        Method const& getY = classRecord.GetMethodViaName("GetY");
        Method const& setX = classRecord.GetMethodViaName("SetX");
        Method const& setY = classRecord.GetMethodViaName("SetY");
        
        RS_ASSERT(getX.GetReturnType().ToIntegral() == GetIntegral(Types::Int32), "Incorrect reflected return type");
        RS_ASSERT(getY.GetReturnType().ToIntegral() == GetIntegral(Types::Int32), "Incorrect reflected return type");
        RS_ASSERT(setX.GetReturnType().ToIntegral() == GetIntegral(Types::Void), "Incorrect reflected return type");
        RS_ASSERT(setY.GetReturnType().ToIntegral() == GetIntegral(Types::Void), "Incorrect reflected return type");
        
        RS_ASSERT(getX.GetArgumentCount() == 0, "Incorrect reflected argument count");
        RS_ASSERT(getY.GetArgumentCount() == 0, "Incorrect reflected argument count");
        RS_ASSERT(setX.GetArgumentCount() == 1, "Incorrect reflected argument count");
        RS_ASSERT(setY.GetArgumentCount() == 1, "Incorrect reflected argument count");
        
        RS_ASSERT(setX.GetArgumentType(0).ToIntegral() == GetIntegral(Types::Int32), "Incorrect reflected argument type");
        RS_ASSERT(setY.GetArgumentType(0).ToIntegral() == GetIntegral(Types::Int32), "Incorrect reflected argument type");        
    }
}